package tools

import (
	"errors"
	"fmt"
	"gitee.com/jjawesomejj/awesome-util/helper/commonhelper"
	"github.com/shirou/gopsutil/cpu"
	"github.com/shirou/gopsutil/mem"
	"net"
	exec2 "os/exec"
	"runtime"
	"strconv"
	"syscall"
	"time"
)

type Kernel interface {
	GetNodeInfo()                                   //获取当前节点信息
	GetNodeRunningTask() int                        //获取当前节点正在运行的节点
	GetNodeMaxRunTask()                             //获取当前节点最大运行节点数
	GetNodeCpuUseAndMemory() map[string]interface{} //获取当前节点的cpu使用率以及内存使用率
	ExecShellOrBash(command string, isAsync bool) (string, error)
	ExecShellOrBashAsync(command string) *exec2.Cmd //异步的执行任务
	GetMac() string
	ExecShellOrBashWithStdWriter(command string, standard *Standard, timeOutFun ...func() (time int, echoWords string, callBack func())) (output string, error error)
}
type WindowsDriver struct {
}
type LinuxDriver struct {
}

/**
获取当前系统剩余的资源
*/
func (driver WindowsDriver) GetNodeCpuUseAndMemory() map[string]interface{} {
	info := map[string]interface{}{}
	memInfo, _ := mem.VirtualMemory()
	info["totalMemory"] = memInfo.Total / (1024 * 1024)
	info["freeMemory"] = memInfo.Available / (1024 * 1024)
	info["usedMemory"] = memInfo.Used / (1024 * 1024)
	info["cpu"] = runtime.NumCPU()
	percent, _ := cpu.Percent(time.Second, false)
	info["cpuUsed"] = percent[0]
	info["currentRun"] = driver.GetNodeRunningTask()
	return info
}
func (driver WindowsDriver) GetMac() string {
	mac := ""
	interfaces, err := net.Interfaces()
	if err != nil {
		panic("Poor soul, here is what you got: " + err.Error())
	}
	for _, inter := range interfaces {
		mac = inter.HardwareAddr.String() //获取本机MAC地址
		break
	}
	return mac
}
func (driver WindowsDriver) GetNodeInfo() {

}
func (driver WindowsDriver) GetNodeRunningTask() int {
	return 0
}
func (driver WindowsDriver) GetNodeMaxRunTask() {

}
func (driver WindowsDriver) ExecShellOrBash(command string, isAysn bool) (string, error) {
	return exec(command, isAysn)
}
func (driver WindowsDriver) ExecShellOrBashAsync(command string) *exec2.Cmd {
	var c *exec2.Cmd
	if IsLinux() {
		c = exec2.Command("bash", "-c", command)
	} else {
		c = exec2.Command("cmd", "/C", command)
	}

	// 此处是windows版本

	return c
}
func (driver LinuxDriver) ExecShellOrBashAsync(command string) *exec2.Cmd {
	var c *exec2.Cmd
	if IsLinux() {
		c = exec2.Command("bash", "-c", command)
	} else {
		c = exec2.Command("cmd", "/C", command)
	}

	// 此处是windows版本

	return c
}
func (driver LinuxDriver) GetNodeCpuUseAndMemory() map[string]interface{} {
	info := map[string]interface{}{}
	memInfo, _ := mem.VirtualMemory()
	info["totalMemory"] = memInfo.Total / (1024 * 1024)
	info["freeMemory"] = memInfo.Available / (1024 * 1024)
	info["usedMemory"] = memInfo.Used / (1024 * 1024)
	info["cpu"] = runtime.NumCPU()

	percent, err := cpu.Percent(time.Second, false)
	if err != nil {
		info["cpuUsed"] = float64(0)
	} else {
		info["cpuUsed"] = percent[0]
	}
	info["currentRun"] = driver.GetNodeRunningTask()
	return info
}
func (driver LinuxDriver) GetNodeRunningTask() int {
	return 0
}
func (driver LinuxDriver) GetNodeInfo() {

}
func (driver LinuxDriver) GetNodeMaxRunTask() {

}
func (driver LinuxDriver) ExecShellOrBash(command string, isAysn bool) (string, error) {
	return exec(command, isAysn)
}
func (driver LinuxDriver) GetMac() string {
	mac := ""
	interfaces, err := net.Interfaces()
	if err != nil {
		panic("Poor soul, here is what you got: " + err.Error())
	}
	for _, inter := range interfaces {
		mac = inter.HardwareAddr.String() //获取本机MAC地址
	}
	return mac
}

func (driver LinuxDriver) ExecShellOrBashWithStdWriter(command string, standard *Standard, timeOutFun ...func() (time int, echoWords string, callBack func())) (string, error) {
	isReturn := false
	defer func() {
		isReturn = true
	}()
	var c *exec2.Cmd
	if IsLinux() {
		c = exec2.Command("bash", "-c", command)
	} else {
		c = exec2.Command("cmd", "/C", command)
	}
	//stdout.Write([]byte("执行命令:" + command + "\n"))
	c.Stdout = standard.Stdout
	c.Stderr = standard.Stderr
	//c.Stdin = standard.StdIn
	var killerr error
	if len(timeOutFun) == 1 && timeOutFun[0] != nil {
		timeOutFunOne := timeOutFun[0]

		timeout, words, fun := timeOutFunOne()
		go func() {
			time.AfterFunc(time.Duration(timeout)*time.Second, func() {
				if isReturn == false {
					//standard.Stdout.Write([]byte(commonhelper.Format("rsync 发送超时耗时:{},检查您的ssh秘钥是否配置正常,或可在配置页添加--timeout= 来设置超时时间\n", string(rune(timeOuts[0])))))
					standard.Stdout.Write([]byte(commonhelper.Format(words+" 耗时:{}", strconv.Itoa(timeout))))
					killerr = errors.New(commonhelper.Format(words+" 耗时:{}", strconv.Itoa(timeout)))
					fmt.Println(killerr, "killerr==>")
					err := c.Process.Signal(syscall.SIGTERM)
					time.Sleep(time.Second * 2)
					c.Process.Kill()
					if fun != nil {
						fun()
					}
					if err != nil {
						return
					}
				}
			})
		}()
	}
	err := c.Run()
	if err != nil {
		return standard.Stdout.GetDataString(), errors.New(commonhelper.Format("err:[{}]stderr:[{}]", err.Error(), standard.Stderr.GetDataString()))
	}
	if killerr != nil {
		return standard.Stdout.GetDataString(), killerr
	}
	return standard.Stdout.GetDataString(), nil
}

func (driver WindowsDriver) ExecShellOrBashWithStdWriter(command string, standard *Standard, timeOutFun ...func() (time int, echoWords string, callBack func())) (string, error) {
	isReturn := false
	defer func() {
		isReturn = true
	}()
	var c *exec2.Cmd
	if IsLinux() {
		c = exec2.Command("bash", "-c", command)
	} else {
		c = exec2.Command("cmd", "/C", command)
	}
	//stdout.Write([]byte("执行命令:" + command + "\n"))
	c.Stdout = standard.Stdout
	c.Stderr = standard.Stderr
	//c.Stdin = standard.StdIn
	if len(timeOutFun) == 1 && timeOutFun[0] != nil {
		go func() {
			timeOutFunOne := timeOutFun[0]
			timeout, words, fun := timeOutFunOne()
			time.AfterFunc(time.Duration(timeout)*time.Second, func() {
				if isReturn == false {
					//standard.Stdout.Write([]byte(commonhelper.Format("rsync 发送超时耗时:{},检查您的ssh秘钥是否配置正常,或可在配置页添加--timeout= 来设置超时时间\n", string(rune(timeOuts[0])))))
					standard.Stdout.Write([]byte(commonhelper.Format(words+" 耗时:{}", string(rune(timeout)))))
					err := c.Process.Signal(syscall.SIGTERM)
					if fun != nil {
						fun()
					}
					if err != nil {
						return
					}
				}
			})
		}()
	}
	err := c.Run()
	if err != nil {
		return standard.Stdout.GetDataString(), errors.New(commonhelper.Format("err:[{}]stderr:[{}]", err.Error(), standard.Stderr.GetDataString()))
	}
	return standard.Stdout.GetDataString(), nil
}

/**
执行系统调用
*/
func exec(command string, isAsync bool) (string, error) {
	var c *exec2.Cmd
	if IsLinux() {
		c = exec2.Command("bash", "-c", command)
	} else {
		c = exec2.Command("cmd", "/C", command)
	}

	std := StdWriter{}
	// 此处是windows版本
	c.Stdout = &std
	err := c.Run()
	if err != nil {
		return string(std.GetDataString()), errors.New(commonhelper.Format("错误码:{},stdout:{}", err.Error(), std.GetDataString()))
	}
	return string(std.GetDataString()), nil

}

/**
判断当前是window还是linux系统
*/
func IsLinux() bool {
	sysType := runtime.GOOS

	if sysType == "linux" {
		// LINUX系统
		return true
	}

	if sysType == "windows" {
		// windows系统
		return false
	}
	return false
}
func GetKernelDriver() Kernel {
	if IsLinux() {
		return LinuxDriver{}
	}
	return WindowsDriver{}
}
